//条件类型

//🐟需要水 鸟需要天空
interface Bird {
    name: '鸟',//字面量类型
}
interface Fish {
    name: '鱼'
}
interface Sky {
    color: '蓝色'
}

interface Water {
    color: '白色'
}

//ts中有一个条件分发的概念 联合类型才会发生条件分发
type MyType<T> = T extends Bird ? Sky : Water;//条件类型就是三元表达式

//type MyType<T> = {name:T} extends {name:Bird|Fish} ? Sky : Water;//条件类型就是三元表达式
//默认都是裸类型 就是这个泛型没有被包裹起来 这时候他是具备分发能力的
//如果泛型被把包裹起来了，就没有分发能里了
type MyBird = MyType<Fish | Bird> //Water|Sky 只有联合类型才能进行分发操作，不是联合脸型

//以下说的内容都是ts中自带的类型 咱们亲自实现一下
//Exclude 从第一个参数排除第二个参数

type Exclude<T, U> = T extends U ? never : T;
type MyExclude = Exclude<string | number | boolean, number | string>

//如果后续想在多的类型中去掉某一个可以考虑到用Exclude类型
type Extract<T, U> = T extends U ? T : never;
type MyExtract = Extract<string | number | boolean, number>

//非空 去掉Null和undefined
let el = document.getElementById('app');
type NonNullable<T> = T extends null | undefined ? never : T;
type MyNon = NonNullable<typeof el>

let xxx: MyNon
//以上都借助了条件类型

interface ICompany {
    name: string,
    address: string
}
interface IPerson {//先定义最大的接口 ——> 小的接口
    name: string,
    age: number,
    company: ICompany
}
//让属性变成可选属性
//type Partial<T> = {[K in keyof T]?:T[K]}
//type MyPartial = Partial<IPerson>;//默认的partial 只递归第一层
type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K] }
type MyPartial = DeepPartial<IPerson>;

let person: MyPartial = {
    company: {
        name: "张三"
    }
}
type Required<T> = { [K in keyof T]-?: T[K] }
type Readonly<T> = { readonly [K in keyof T]: T[K] }
type OptionalPerson = Readonly<Required<Partial<IPerson>>>;//去掉？ 去掉问好 变成仅读的

//Pick 挑选出想要的结果
//type Pick<T extends object,K extends keyof T> = {[P in K]:T[P]}
type MyPerson = Pick<IPerson, 'name' | 'age'>;//'name'|'page' => {name:IPerson[name],age:IPerson[name]}
//就是在对象中取出需要的属性 挑选

type MyPerson2 = Omit<IPerson, 'age'>

function map<T extends keyof any, K, U>(obj: Record<T, K>, fn: (item: K, ley: T) => U): Record<T, U> {
    let result = {} as Record<T, U>;
    for (let key in obj) {
        result[key] = fn(obj[key], key)
    }
    return result;
}
//record 记录 可以描述对象类型
let obj = map({ name: 'zf', age: 12 }, function (item, key) {//name => abc age=>abc
    return 'abc'
});//map方法 给一个对象转化成另一个对象


//Exclude Extract NonNullable Partial readonly required
//Pick Omit Record


//类型推断infer
function getPointer(x: string, y: string, z: string) {
    return { x, y, z }
}
//typeof keyof extends in ? -? readonly
type ReturnType<T extends (...args: any[]) => any> = (...args: any[]) => any
type MyReturn = ReturnType<typeof getPointer>


//info 可以根据内容位置进行推断结果的类型

//高级类型：unknown 我们可以用unknown替换掉any,unknown是any的安全类型

let a: any = 1;//类和类型都可以赋值给unknow 但是any不够安全 因为可以调用属性 但是unknown 一般不能进行取值操作
//使用的时候 尽量用unknow来替换掉any类型
type a = unknown | string //和任何类型做联合类型都是unknow,unknow和其他类型做交集获取的永远是其他类型 

type xx = never extends unknown ? true : false

export { }

